package com.stars.easyms.datasource.mybatis;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.apache.ibatis.type.TypeException;

import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>className: EasyMsMybatisTypeAliasRegistry</p>
 * <p>description: EasyMs的Mybatis的类型别名注测定制化服务类</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019-07-10 11:13
 */
@Slf4j
final class EasyMsMybatisTypeAliasRegistry extends TypeAliasRegistry {

    private static final Map<String, Class<?>> TYPE_ALIASES = new ConcurrentHashMap<>(512);

    @SuppressWarnings("unchecked")
    @Override
    public <T> Class<T> resolveAlias(String string) {
        try {
            if (string == null) {
                return null;
            }
            String key = string.toLowerCase(Locale.ENGLISH);
            Class<T> value;
            if (TYPE_ALIASES.containsKey(key)) {
                value = (Class<T>) TYPE_ALIASES.get(key);
            } else {
                value = (Class<T>) Resources.classForName(string);
            }
            return value;
        } catch (ClassNotFoundException e) {
            throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
        }
    }

    @Override
    public void registerAlias(String alias, Class<?> value) {
        if (alias == null) {
            throw new TypeException("The parameter alias cannot be null");
        }
        String key = alias.toLowerCase(Locale.ENGLISH);
        if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
            String newKey = value.getName();
            if (log.isDebugEnabled()) {
                log.debug("The alias '{}' is already mapped to the value '{}', now use alias '{}'.",
                        alias, TYPE_ALIASES.get(key).getName(), newKey);
            }
            TYPE_ALIASES.put(newKey, value);
        } else {
            TYPE_ALIASES.put(key, value);
        }
    }

    @Override
    public void registerAliases(String packageName, Class<?> superType) {
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
        resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
        Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
        for (Class<?> type : typeSet) {
            try {
                if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
                    registerAlias(type);
                }
            } catch (Throwable e) {
                // ignore
            }
        }
    }

    @Override
    public Map<String, Class<?>> getTypeAliases() {
        return Collections.unmodifiableMap(TYPE_ALIASES);
    }
}